home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / cal.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  8KB  |  304 lines

  1. /* cal - print a calendar        Author: Maritn Minow */
  2.  
  3. #include <stdio.h>
  4.  
  5. #define do3months    domonth
  6. #define    IO_SUCCESS    0    /* Unix definitions         */
  7. #define    IO_ERROR    1
  8. #define    EOS    0
  9.  
  10. #define    ENTRY_SIZE    3    /* 3 bytes per value         */
  11. #define DAYS_PER_WEEK    7    /* Sunday, etc.             */
  12. #define    WEEKS_PER_MONTH    6    /* Max. weeks in a month     */
  13. #define    MONTHS_PER_LINE    3    /* Three months across         */
  14. #define    MONTH_SPACE    3    /* Between each month         */
  15.  
  16. char *badarg = {"Bad argument\n"};
  17. char *how = {"Usage: cal [month] year\n"};
  18.  
  19. /* Calendar() stuffs data into layout[],
  20.  * output() copies from layout[] to outline[], (then trims blanks).
  21.  */
  22. char layout[MONTHS_PER_LINE][WEEKS_PER_MONTH][DAYS_PER_WEEK][ENTRY_SIZE];
  23. char outline[(MONTHS_PER_LINE * DAYS_PER_WEEK * ENTRY_SIZE)
  24.        + (MONTHS_PER_LINE * MONTH_SPACE)
  25.        + 1];
  26.  
  27. char *weekday = " S  M Tu  W Th  F  S";
  28. char *monthname[] = {
  29.          "???",        /* No month 0     */
  30.          "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  31.          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  32. };
  33.  
  34. main(argc, argv)
  35. int argc;
  36. char *argv[];
  37. {
  38.   register int month;
  39.   register int year;
  40.  
  41.   register int arg1val;
  42.   int arg1len;
  43.   int arg2val;
  44.  
  45.   if (argc <= 1) {
  46.     usage(how);
  47.   } else {
  48.     arg1val = atoi(argv[1]);
  49.     arg1len = strlen(argv[1]);
  50.     if (argc == 2) {
  51.         /* Only one argument, if small, it's a month.  If
  52.          * large, it's a year.  Note: cal        0082    Year
  53.          * 0082 cal        82    Year 0082 */
  54.         if (arg1len <= 2 && arg1val <= 12)
  55.             do3months(year, arg1val);
  56.         else
  57.             doyear(arg1val);
  58.     } else {
  59.         /* Two arguments, allow 1980 12 or 12 1980 */
  60.         arg2val = atoi(argv[2]);
  61.         if (arg1len > 2)
  62.             do3months(arg1val, arg2val);
  63.         else
  64.             do3months(arg2val, arg1val);
  65.     }
  66.   }
  67.   exit(IO_SUCCESS);
  68. }
  69.  
  70. doyear(year)
  71. int year;
  72. /* Print the calendar for an entire year. */
  73. {
  74.   register int month;
  75.  
  76.   if (year < 1 || year > 9999) usage(badarg);
  77.   if (year < 100)
  78.     printf("\n\n\n                                 00%2d\n\n", year);
  79.   else
  80.     printf("\n\n\n%35d\n\n", year);
  81.   for (month = 1; month <= 12; month += MONTHS_PER_LINE) {
  82.     printf("%12s%23s%23s\n",
  83.            monthname[month],
  84.            monthname[month + 1],
  85.            monthname[month + 2]);
  86.     printf("%s   %s   %s\n", weekday, weekday, weekday);
  87.     calendar(year, month + 0, 0);
  88.     calendar(year, month + 1, 1);
  89.     calendar(year, month + 2, 2);
  90.     output(3);
  91. #if MONTHS_PER_LINE != 3
  92. #error  "the above will not work"
  93. #endif
  94.   }
  95.   printf("\n\n\n");
  96. }
  97.  
  98. domonth(year, month)
  99. int year;
  100. int month;
  101. /* Do one specific month -- note: no longer used */
  102. {
  103.   if (year < 1 || year > 9999) usage(badarg);
  104.   if (month <= 0 || month > 12) usage(badarg);
  105.   printf("%9s%5d\n\n%s\n", monthname[month], year, weekday);
  106.   calendar(year, month, 0);
  107.   output(1);
  108.   printf("\n\n");
  109. }
  110.  
  111. output(nmonths)
  112. int nmonths;            /* Number of months to do     */
  113. /* Clean up and output the text. */
  114. {
  115.   register int week;
  116.   register int month;
  117.   register char *outp;
  118.   int i;
  119.   char tmpbuf[21], *p;
  120.  
  121.   for (week = 0; week < WEEKS_PER_MONTH; week++) {
  122.     outp = outline;
  123.     for (month = 0; month < nmonths; month++) {
  124.         /* The -1 in the following removes the unwanted
  125.          * leading blank from the entry for Sunday. */
  126.         p = &layout[month][week][0][1];
  127.         for (i = 0; i < 20; i++) tmpbuf[i] = *p++;
  128.         tmpbuf[20] = 0;
  129.         sprintf(outp, "%s   ", tmpbuf);
  130.         outp += (DAYS_PER_WEEK * ENTRY_SIZE) + MONTH_SPACE - 1;
  131.     }
  132.     while (outp > outline && outp[-1] == ' ') outp--;
  133.     *outp = EOS;
  134.     puts(outline);
  135.   }
  136. }
  137.  
  138. calendar(year, month, index)
  139. int year;
  140. int month;
  141. int index;            /* Which of the three months         */
  142. /* Actually build the calendar for this month. */
  143. {
  144.   register char *tp;
  145.   int week;
  146.   register int wday;
  147.   register int today;
  148.  
  149.   setmonth(year, month);
  150.   for (week = 0; week < WEEKS_PER_MONTH; week++) {
  151.     for (wday = 0; wday < DAYS_PER_WEEK; wday++) {
  152.         tp = &layout[index][week][wday][0];
  153.         *tp++ = ' ';
  154.         today = getdate(week, wday);
  155.         if (today <= 0) {
  156.             *tp++ = ' ';
  157.             *tp++ = ' ';
  158.         } else if (today < 10) {
  159.             *tp++ = ' ';
  160.             *tp = (today + '0');
  161.         } else {
  162.             *tp++ = (today / 10) + '0';
  163.             *tp = (today % 10) + '0';
  164.         }
  165.     }
  166.   }
  167. }
  168.  
  169. usage(s)
  170. char *s;
  171. {
  172. /* Fatal parameter error. */
  173.  
  174.   fprintf(stderr, "%s", s);
  175.   exit(IO_ERROR);
  176. }
  177.  
  178. /* Calendar routines, intended for eventual porting to TeX
  179.  *
  180.  * date(year, month, week, wday)
  181.  *    Returns the date on this week (0 is first, 5 last possible)
  182.  *    and day of the week (Sunday == 0)
  183.  *    Note: January is month 1.
  184.  *
  185.  * setmonth(year, month)
  186.  *    Parameters are as above, sets getdate() for this month.
  187.  *
  188.  * int
  189.  * getdate(week, wday)
  190.  *    Parameters are as above, uses the data set by setmonth()
  191.  */
  192.  
  193. /* This structure is used to pass data between setmonth() and getdate().
  194.  * It needs considerable expansion if the Julian->Gregorian change is
  195.  * to be extended to other countries.
  196.  */
  197.  
  198. static struct {
  199.   int this_month;        /* month number used in 1752 checking     */
  200.   int feb;            /* Days in February for this month     */
  201.   int sept;            /* Days in September for this month     */
  202.   int days_in_month;        /* Number of days in this month         */
  203.   int dow_first;        /* Day of week of the 1st day in month     */
  204. } info;
  205.  
  206. static int day_month[] = {    /* 30 days hath September...         */
  207.           0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  208. };
  209.  
  210. int date(year, month, week, wday)
  211. int year;            /* Calendar date being computed         */
  212. int month;            /* January == 1                 */
  213. int week;            /* Week in the month 0..5 inclusive     */
  214. int wday;            /* Weekday, Sunday == 0             */
  215. /* Return the date of the month that fell on this week and weekday.
  216.  * Return zero if it's out of range.
  217.  */
  218. {
  219.   setmonth(year, month);
  220.   return(getdate(week, wday));
  221. }
  222.  
  223. setmonth(year, month)
  224. int year;            /* Year to compute         */
  225. int month;            /* Month, January is month 1     */
  226. /* Setup the parameters needed to compute this month
  227.  * (stored in the info structure).
  228.  */
  229. {
  230.   register int i;
  231.  
  232.   if (month < 1 || month > 12) {/* Verify caller's parameters     */
  233.     info.days_in_month = 0;    /* Garbage flag             */
  234.     return;
  235.   }
  236.   info.this_month = month;    /* used in 1752    checking     */
  237.   info.dow_first = Jan1(year);    /* Day of January 1st for now     */
  238.   info.feb = 29;        /* Assume leap year         */
  239.   info.sept = 30;        /* Assume normal year         */
  240.   /* Determine whether it's an ordinary year, a leap year or the
  241.    * magical calendar switch year of 1752. */
  242.   switch ((Jan1(year + 1) + 7 - info.dow_first) % 7) {
  243.       case 1:            /* Not a leap year         */
  244.     info.feb = 28;
  245.       case 2:            /* Ordinary leap year         */
  246.     break;
  247.  
  248.       default:            /* The magical moment arrives     */
  249.     info.sept = 19;        /* 19 days hath September     */
  250.     break;
  251.   }
  252.   info.days_in_month =
  253.     (month == 2) ? info.feb
  254.     : (month == 9) ? info.sept
  255.     : day_month[month];
  256.   for (i = 1; i < month; i++) {
  257.     switch (i) {        /* Special months?         */
  258.         case 2:        /* February             */
  259.         info.dow_first += info.feb;
  260.         break;
  261.  
  262.         case 9:    info.dow_first += info.sept;    break;
  263.  
  264.         default:
  265.         info.dow_first += day_month[i];
  266.         break;
  267.     }
  268.   }
  269.   info.dow_first %= 7;        /* Now it's Sunday to Saturday     */
  270. }
  271.  
  272. int getdate(week, wday)
  273. int week;
  274. int wday;
  275. {
  276.   register int today;
  277.  
  278.   /* Get a first guess at today's date and make sure it's in range. */
  279.   today = (week * 7) + wday - info.dow_first + 1;
  280.   if (today <= 0 || today > info.days_in_month)
  281.     return(0);
  282.   else if (info.sept == 19 && info.this_month == 9
  283.      && today >= 3)        /* The magical month?     */
  284.     return(today + 11);    /* If so, some dates changed     */
  285.   else                /* Otherwise,             */
  286.     return(today);        /* Return the date         */
  287. }
  288.  
  289. static int Jan1(year)
  290. int year;
  291. /* Return day of the week for Jan 1 of the specified year. */
  292. {
  293.   register int day;
  294.  
  295.   day = year + 4 + ((year + 3) / 4);    /* Julian Calendar     */
  296.   if (year > 1800) {        /* If it's recent, do     */
  297.     day -= ((year - 1701) / 100);    /* Clavian correction     */
  298.     day += ((year - 1601) / 400);    /* Gregorian correction     */
  299.   }
  300.   if (year > 1752)        /* Adjust for Gregorian     */
  301.     day += 3;        /* calendar         */
  302.   return(day % 7);
  303. }
  304.